{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Part 3: 高级远程执行工具\n",
    "\n",
    "在上一节中，我们使用联合学习训练了一个玩具模型。 为此，我们在模型上调用了.send()和.get()，将其发送到训练数据的位置，对其进行了更新，最后将其恢复。但是，在示例的最后，我们意识到我们需要进一步保护人们的隐私。也就是说，我们要在调用.get()之前对梯度进行平均。这样，我们将永远不会看到任何人的确切坡度（因此更好地保护了他们的隐私！！！）\n",
    "\n",
    "但是，为了做到这一点，我们还需要几块：\n",
    "\n",
    "- 使用指针将张量直接发送给其他工作机\n",
    "\n",
    "此外，当我们在这里时，我们还将学习一些更高级的张量操作，这将有助于我们使用本示例以及将来的一些示例！\n",
    "\n",
    "作者:\n",
    "- Andrew Trask - Twitter: [@iamtrask](https://twitter.com/iamtrask)\n",
    "\n",
    "中文版译者：\n",
    "- Hou Wei - github：[@dljgs1](https://github.com/dljgs1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch\n",
    "import syft as sy\n",
    "hook = sy.TorchHook(torch)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 3.1 - 指向指针的指针\n",
    "\n",
    "如您所知，PointerTensor（张量指针）对象的感觉就像普通的张量一样。实际上，它们非常类似于张量，甚至我们甚至可以拥有**指向这些指针**的指针。一探究竟！"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bob = sy.VirtualWorker(hook, id='bob')\n",
    "alice = sy.VirtualWorker(hook, id='alice')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 这是本地张量\n",
    "x = torch.tensor([1,2,3,4])\n",
    "x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 将本地张量发送给bob\n",
    "x_ptr = x.send(bob)\n",
    "\n",
    "# 新的指针\n",
    "x_ptr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 现在我们可以把 指 针 发 送 给Alice!!!\n",
    "pointer_to_x_ptr = x_ptr.send(alice)\n",
    "\n",
    "pointer_to_x_ptr"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 发生了什么?\n",
    "\n",
    "在之前的示例中我们创建了一个名为 `x` 的张量然后发送给了Bob，并在本地计算机创建了一个指针(`x_ptr`)。\n",
    "\n",
    "然后我们调用了 `x_ptr.send(alice)` ，它将**指针**发送给Alice。 \n",
    "\n",
    "注意，这里**没有**移动数据，而是将指针移动到了数据上。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 如上所示，Bob仍然具有实际数据（数据始终以LocalTensor类型存储）。\n",
    "bob._objects"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 另一方面，Alice有x_ptr！ （注意它是如何指向Bob的）\n",
    "alice._objects"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 我们可以用 .get() 获取 x_ptr 返回给 Alice\n",
    "\n",
    "x_ptr = pointer_to_x_ptr.get()\n",
    "x_ptr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 我们可以用 x_ptr 获取x返回给 Bob!\n",
    "\n",
    "x = x_ptr.get()\n",
    "x"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Pointer -> Pointer -> Data 对象上的运算\n",
    "\n",
    "就像普通的指针一样，我们可以在这些张量上执行任何PyTorch操作。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bob._objects"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "alice._objects"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "p2p2x = torch.tensor([1,2,3,4,5]).send(bob).send(alice)\n",
    "\n",
    "y = p2p2x + p2p2x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bob._objects"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "alice._objects"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "y.get().get()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bob._objects"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "alice._objects"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "p2p2x.get().get()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bob._objects"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "alice._objects"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 3.2 - 指针链操作\n",
    "\n",
    "因此，在上一节中，每当我们调用.send()或.get()操作时，它都会直接在本地计算机的张量上调用该操作。但是，如果您有一连串的指针，有时您希望在该链中“最后”指针上调用.get()或.send()之类的操作（例如，将数据直接从一个工作程序发送到另一个工作程序）。为此，您想使用专门为此隐私保护操作设计的功能。\n",
    "\n",
    "这些操作是：\n",
    "\n",
    "- `my_pointer2pointer.move(another_worker)`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# x is now a pointer to a pointer to the data which lives on Bob's machine\n",
    "# x现在是指向数据的指针，存在Bob的机器上\n",
    "x = torch.tensor([1,2,3,4,5]).send(bob)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print('  bob:', bob._objects)\n",
    "print('alice:',alice._objects)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = x.move(alice)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print('  bob:', bob._objects)\n",
    "print('alice:',alice._objects)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "太棒了! 现在我们有了足够的工具来实现在受信任聚合器下的**模型平均**！"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 恭喜!!! 是时候加入社区了!\n",
    "\n",
    "祝贺您完成本笔记本教程！ 如果您喜欢此方法，并希望加入保护隐私、去中心化AI和AI供应链（数据）所有权的运动，则可以通过以下方式做到这一点！\n",
    "\n",
    "### 给 PySyft 加星\n",
    "\n",
    "帮助我们的社区的最简单方法是仅通过给GitHub存储库加注星标！ 这有助于提高人们对我们正在构建的出色工具的认识。\n",
    "\n",
    "- [Star PySyft](https://github.com/OpenMined/PySyft)\n",
    "\n",
    "### 加入我们的 Slack!\n",
    "\n",
    "保持最新进展的最佳方法是加入我们的社区！ 您可以通过填写以下表格来做到这一点[http://slack.openmined.org](http://slack.openmined.org)\n",
    "\n",
    "### 加入代码项目!\n",
    "\n",
    "对我们的社区做出贡献的最好方法是成为代码贡献者！ 您随时可以转到PySyft GitHub的Issue页面并过滤“projects”。这将向您显示所有概述，选择您可以加入的项目！如果您不想加入项目，但是想做一些编码，则还可以通过搜索标记为“good first issue”的GitHub问题来寻找更多的“一次性”微型项目。\n",
    "\n",
    "- [PySyft Projects](https://github.com/OpenMined/PySyft/issues?q=is%3Aopen+is%3Aissue+label%3AProject)\n",
    "- [Good First Issue Tickets](https://github.com/OpenMined/PySyft/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22)\n",
    "\n",
    "### 捐赠\n",
    "\n",
    "如果您没有时间为我们的代码库做贡献，但仍想提供支持，那么您也可以成为Open Collective的支持者。所有捐款都将用于我们的网络托管和其他社区支出，例如黑客马拉松和聚会！\n",
    "\n",
    "[OpenMined's Open Collective Page](https://opencollective.com/openmined)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.4"
  },
  "latex_envs": {
   "LaTeX_envs_menu_present": true,
   "autoclose": false,
   "autocomplete": true,
   "bibliofile": "biblio.bib",
   "cite_by": "apalike",
   "current_citInitial": 1,
   "eqLabelWithNumbers": true,
   "eqNumInitial": 1,
   "hotkeys": {
    "equation": "Ctrl-E",
    "itemize": "Ctrl-I"
   },
   "labels_anchors": false,
   "latex_user_defs": false,
   "report_style_numbering": false,
   "user_envs_cfg": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
